/**
 * @author <a href=mailto:volkodavav@gmail.com>volkodavav</a>
 */
package com.demo.model.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;

import com.demo.model.dao.CustomerDAO;
import com.demo.model.dao.ICrudDAO;
import com.demo.model.service.validations.BirthdayAfterPresentException;
import com.demo.model.service.validations.BirthdayUnder18Exception;
import com.demo.model.service.validations.EmailFormatException;
import com.demo.model.service.validations.GenderNoModifiableException;
import com.demo.model.service.validations.LicenseChangeException;
import com.demo.model.service.validations.NullException;
import com.demo.model.service.validations.StringLengthException;
import com.demo.pojo.Customer;

@ManagedBean(name = "customerServiceImpl")
@ApplicationScoped
public class CustomerServiceImpl implements ICustomerService
{
    @ManagedProperty("#{customerDAO}")
    private ICrudDAO<Customer, Integer> dao;
    public static final int MIN_NAME_LENGTH = 5;
    public static final int MAX_NAME_LENGTH = 30;
    public static final int MIN_AGE = 18;
    public static final int MIN_ABOUT_LENGTH = 0;
    public static final int MAX_ABOUT_LENGTH = 250;
    
    public static final String NAME = "Nombre";
    public static final String BIRTHDAY = "La Fecha de Cumpleaños";
    public static final String GENDER = "Genero";
    public static final String ABOUT = "About";
    public static final String CARD = "La Tarjeta de Credito";
    public static final String EMAIL = "Correo Electronico";
    public static final String MAILING_LIST = "Mailing List";
    
    @Override
    public long count()
    {
        return this.dao.count();
    }

    @Override
    public Customer create()
    {
        return this.dao.create();
    }

    @Override
    public void delete(Customer entity)
    {
        this.dao.delete(entity);
    }

    @Override
    public int deleteAll()
    {
        return this.dao.deleteAll();
    }

    @Override
    public List<Customer> findAll()
    {
        return new ArrayList<Customer>(this.dao.findAll());
    }

    @Override
    public Customer findById(Integer id)
    {
        return this.dao.findById(id);
    }

    @PostConstruct
    public void postConstruct()
    {
        if (this.dao == null)
        {
            this.dao = new CustomerDAO();
            System.err.println("*** WARNING *** Dao not injected.");
        }
    }

    @PreDestroy
    public void preDestroy()
    {
        this.dao = null;
    }

    @Override
    public void save(Customer entity)
    {
        this.dao.save(entity);
    }

    public void setDao(ICrudDAO<Customer, Integer> dao)
    {
        this.dao = dao;
    }

    @Override
    public Customer update(Customer entity)
    {
        Customer clientReturn = this.create();
        
        if (this.dao.findAll().isEmpty()) {
            return clientReturn;
        }
        
        try {
            validateNameLogic(entity);
            validateBirthdayLogic(entity);
            validateGenderLogic(entity);
            validateAboutLogic(entity);
            validateEmailLogic(entity);
            validateCreditCardLogic(entity);
            validateLicenseLogic(entity);
            validateMailingListLogic(entity);
            clientReturn = this.dao.update(entity);
        } catch (LicenseChangeException e) {
            System.out.println(e.getMessage());
        } catch (GenderNoModifiableException e) {
            System.out.println(e.getMessage());
        } catch (BirthdayAfterPresentException e) {
            System.out.println(e.getMessage());
        } catch (BirthdayUnder18Exception e) {
            System.out.println(e.getMessage());
        } catch (NullException e) {
            System.out.println(e.getMessage());
        } catch (StringLengthException e) {
            System.out.println(e.getMessage());
        } catch (EmailFormatException e) {
            System.out.println(e.getMessage());
        }
        
        return clientReturn;
    }
    
    private void validateNameLogic(Customer entity) throws StringLengthException {
        String name = entity.getName();
        if (name.length() < MIN_NAME_LENGTH || name.length() > MAX_NAME_LENGTH) {
            throw new StringLengthException(NAME, MIN_NAME_LENGTH, MAX_NAME_LENGTH);
        }
    }
    
    private void validateBirthdayLogic(Customer entity) throws BirthdayAfterPresentException, NullException, BirthdayUnder18Exception {
        if ( entity.getBirthday() == null) {
            throw new NullException(BIRTHDAY);
        }
        
        Calendar calendar = new GregorianCalendar();
        final int año = calendar.get(Calendar.YEAR);
        
        Date fechaCliente = entity.getBirthday();
        Calendar calendarCliente = new GregorianCalendar();
        calendarCliente.setTime(fechaCliente);
        
        if (año - MIN_AGE <= calendarCliente.get(Calendar.YEAR)) {
            throw new BirthdayUnder18Exception();
        }
        
        Date fechaSistema = this.findById(entity.getId()).getBirthday();
        if (entity.getBirthday().compareTo(fechaSistema) > 0) {
            throw new BirthdayAfterPresentException();
        }
    }
    
    private void validateGenderLogic(Customer entity) throws NullException, GenderNoModifiableException {

        if ( entity.getGender() == null) {
            throw new NullException(GENDER);
        }
        
        Customer clienteSistema = this.findById(entity.getId());
        
        if (!clienteSistema.getGender().equals(entity.getGender())) {
            throw new GenderNoModifiableException();
        }
    }
    
    private void validateAboutLogic(Customer entity) throws StringLengthException {
        int lengthAbout = entity.getAbout().length();
        if ( lengthAbout > MAX_ABOUT_LENGTH) {
            throw new StringLengthException(ABOUT, MIN_ABOUT_LENGTH, MAX_ABOUT_LENGTH);
        }
    }
    
    private void validateCreditCardLogic(Customer entity) throws NullException {
        if ( entity.getCard() == null) {
            throw new NullException(CARD);
        }
    }
    
    private void validateLicenseLogic(Customer entity) throws LicenseChangeException {
        if ( !entity.getLicense()) {
            throw new LicenseChangeException();
        }
    }
    
    private void validateEmailLogic(Customer entity) throws NullException, EmailFormatException {
        if ( entity.getEmail() == null) {
            throw new NullException(EMAIL);
        }
        final String EMAIL_PATTERN = 
                "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
                + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
        
        Pattern pattern = Pattern.compile(EMAIL_PATTERN);;
        Matcher matcher;
        
        matcher = pattern.matcher(entity.getEmail());
        if (!matcher.matches()) {
            throw new EmailFormatException();
        }

    }
    
    private void validateMailingListLogic(Customer entity) throws NullException {
        if ( entity.getMailingList() == null) {
            throw new NullException(MAILING_LIST);
        }
    }
}